﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using IPC.Communication.BasicFramework;
using IPC.Communication.Core;
using IPC.Communication.Core.IMessage;
using IPC.Communication.Core.Net;
using IPC.Communication.Reflection;

namespace IPC.Communication.Profinet.Melsec
{
    public class MelsecA1EAsciiNet : NetworkDeviceBase
    {
        private byte _PLCNumber = byte.MaxValue;
        public byte PLCNumber
        {
            get { return _PLCNumber; }
            set { _PLCNumber = value; }
        }


        public MelsecA1EAsciiNet()
        {
            base.WordLength = 1;
            LogMsgFormatBinary = false;
            base.ByteTransform = new RegularByteTransform();
        }

        public MelsecA1EAsciiNet(string ipAddress, int port)
        {
            base.WordLength = 1;
            IpAddress = ipAddress;
            Port = port;
            LogMsgFormatBinary = false;
            base.ByteTransform = new RegularByteTransform();
        }

        protected override INetMessage GetNewNetMessage()
        {
            return new MelsecA1EAsciiMessage();
        }

        [HslMqttApi("ReadByteArray", "")]
        public override OperateResult<byte[]> Read(string address, ushort length)
        {
            bool isBit = false;
            OperateResult<byte[]> operateResult = BuildReadCommand(address, length, isBit = false, PLCNumber);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            OperateResult<byte[]> operateResult2 = ReadFromCoreServer(operateResult.Content);
            if (!operateResult2.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult2);
            }
            OperateResult operateResult3 = CheckResponseLegal(operateResult2.Content);
            if (!operateResult3.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult3);
            }
            return ExtractActualData(operateResult2.Content, isBit: false);
        }

        [HslMqttApi("WriteByteArray", "")]
        public override OperateResult Write(string address, byte[] value)
        {
            OperateResult<byte[]> operateResult = BuildWriteWordCommand(address, value, PLCNumber);
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            OperateResult<byte[]> operateResult2 = ReadFromCoreServer(operateResult.Content);
            if (!operateResult2.IsSuccess)
            {
                return operateResult2;
            }
            OperateResult operateResult3 = CheckResponseLegal(operateResult2.Content);
            if (!operateResult3.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult3);
            }
            return OperateResult.CreateSuccessResult();
        }

        //[AsyncStateMachine(typeof(<ReadAsync>d__9))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult<byte[]>> ReadAsync(string address, ushort length)
        //{
        //    <ReadAsync>d__9 stateMachine = new <ReadAsync>d__9();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte[]>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.length = length;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<WriteAsync>d__10))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult> WriteAsync(string address, byte[] value)
        //{
        //    <WriteAsync>d__10 stateMachine = new <WriteAsync>d__10();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.value = value;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        [HslMqttApi("ReadBoolArray", "")]
        public override OperateResult<bool[]> ReadBool(string address, ushort length)
        {
            bool isBit = true;
            OperateResult<byte[]> operateResult = BuildReadCommand(address, length, isBit = true, PLCNumber);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<bool[]>(operateResult);
            }
            OperateResult<byte[]> operateResult2 = ReadFromCoreServer(operateResult.Content);
            if (!operateResult2.IsSuccess)
            {
                return OperateResult.CreateFailedResult<bool[]>(operateResult2);
            }
            OperateResult operateResult3 = CheckResponseLegal(operateResult2.Content);
            if (!operateResult3.IsSuccess)
            {
                return OperateResult.CreateFailedResult<bool[]>(operateResult3);
            }
            OperateResult<byte[]> operateResult4 = ExtractActualData(operateResult2.Content, isBit: true);
            if (!operateResult4.IsSuccess)
            {
                return OperateResult.CreateFailedResult<bool[]>(operateResult4);
            }
            return OperateResult.CreateSuccessResult(operateResult4.Content.Select((byte m) => m == 1).Take(length).ToArray());
        }

        [HslMqttApi("WriteBoolArray", "")]
        public override OperateResult Write(string address, bool[] values)
        {
            OperateResult<byte[]> operateResult = BuildWriteBoolCommand(address, values, PLCNumber);
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            OperateResult<byte[]> operateResult2 = ReadFromCoreServer(operateResult.Content);
            if (!operateResult2.IsSuccess)
            {
                return operateResult2;
            }
            return CheckResponseLegal(operateResult2.Content);
        }

        //[AsyncStateMachine(typeof(<ReadBoolAsync>d__13))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult<bool[]>> ReadBoolAsync(string address, ushort length)
        //{
        //    <ReadBoolAsync>d__13 stateMachine = new <ReadBoolAsync>d__13();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<bool[]>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.length = length;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<WriteAsync>d__14))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult> WriteAsync(string address, bool[] values)
        //{
        //    <WriteAsync>d__14 stateMachine = new <WriteAsync>d__14();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.values = values;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        public override string ToString()
        {
            return String.Format("MelsecA1ENet[{0}:{1}]", IpAddress, Port);
        }

        public static OperateResult<byte[]> BuildReadCommand(string address, ushort length, bool isBit, byte plcNumber)
        {
            OperateResult<MelsecA1EDataType, int> operateResult = MelsecHelper.McA1EAnalysisAddress(address);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            byte value = (byte)((!isBit) ? 1 : 0);
            return OperateResult.CreateSuccessResult(new byte[24]
		{
			SoftBasic.BuildAsciiBytesFrom(value)[0],
			SoftBasic.BuildAsciiBytesFrom(value)[1],
			SoftBasic.BuildAsciiBytesFrom(plcNumber)[0],
			SoftBasic.BuildAsciiBytesFrom(plcNumber)[1],
			48,
			48,
			48,
			65,
			SoftBasic.BuildAsciiBytesFrom(operateResult.Content1.DataCode[0])[0],
			SoftBasic.BuildAsciiBytesFrom(operateResult.Content1.DataCode[0])[1],
			SoftBasic.BuildAsciiBytesFrom(operateResult.Content1.DataCode[1])[0],
			SoftBasic.BuildAsciiBytesFrom(operateResult.Content1.DataCode[1])[1],
			SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[3])[0],
			SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[3])[1],
			SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[2])[0],
			SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[2])[1],
			SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[1])[0],
			SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[1])[1],
			SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[0])[0],
			SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[0])[1],
			SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes((int)length % 256)[0])[0],
			SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes((int)length % 256)[0])[1],
			48,
			48
		});
        }

        public static OperateResult<byte[]> BuildWriteWordCommand(string address, byte[] value, byte plcNumber)
        {
            OperateResult<MelsecA1EDataType, int> operateResult = MelsecHelper.McA1EAnalysisAddress(address);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            value = MelsecHelper.TransByteArrayToAsciiByteArray(value);
            byte[] array = new byte[24 + value.Length];
            array[0] = 48;
            array[1] = 51;
            array[2] = SoftBasic.BuildAsciiBytesFrom(plcNumber)[0];
            array[3] = SoftBasic.BuildAsciiBytesFrom(plcNumber)[1];
            array[4] = 48;
            array[5] = 48;
            array[6] = 48;
            array[7] = 65;
            array[8] = SoftBasic.BuildAsciiBytesFrom(operateResult.Content1.DataCode[0])[0];
            array[9] = SoftBasic.BuildAsciiBytesFrom(operateResult.Content1.DataCode[0])[1];
            array[10] = SoftBasic.BuildAsciiBytesFrom(operateResult.Content1.DataCode[1])[0];
            array[11] = SoftBasic.BuildAsciiBytesFrom(operateResult.Content1.DataCode[1])[1];
            array[12] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[3])[0];
            array[13] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[3])[1];
            array[14] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[2])[0];
            array[15] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[2])[1];
            array[16] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[1])[0];
            array[17] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[1])[1];
            array[18] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[0])[0];
            array[19] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[0])[1];
            array[20] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(value.Length / 4)[0])[0];
            array[21] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(value.Length / 4)[0])[1];
            array[22] = 48;
            array[23] = 48;
            value.CopyTo(array, 24);
            return OperateResult.CreateSuccessResult(array);
        }

        public static OperateResult<byte[]> BuildWriteBoolCommand(string address, bool[] value, byte plcNumber)
        {
            OperateResult<MelsecA1EDataType, int> operateResult = MelsecHelper.McA1EAnalysisAddress(address);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            byte[] array = value.Select((bool m) => (byte)(m ? 49 : 48)).ToArray();
            if (array.Length % 2 == 1)
            {
                array = SoftBasic.SpliceArray<byte>(array, new byte[1]
			{
				48
			});
            }
            byte[] array2 = new byte[24 + array.Length];
            array2[0] = 48;
            array2[1] = 50;
            array2[2] = SoftBasic.BuildAsciiBytesFrom(plcNumber)[0];
            array2[3] = SoftBasic.BuildAsciiBytesFrom(plcNumber)[1];
            array2[4] = 48;
            array2[5] = 48;
            array2[6] = 48;
            array2[7] = 65;
            array2[8] = SoftBasic.BuildAsciiBytesFrom(operateResult.Content1.DataCode[0])[0];
            array2[9] = SoftBasic.BuildAsciiBytesFrom(operateResult.Content1.DataCode[0])[1];
            array2[10] = SoftBasic.BuildAsciiBytesFrom(operateResult.Content1.DataCode[1])[0];
            array2[11] = SoftBasic.BuildAsciiBytesFrom(operateResult.Content1.DataCode[1])[1];
            array2[12] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[3])[0];
            array2[13] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[3])[1];
            array2[14] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[2])[0];
            array2[15] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[2])[1];
            array2[16] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[1])[0];
            array2[17] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[1])[1];
            array2[18] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[0])[0];
            array2[19] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(operateResult.Content2)[0])[1];
            array2[20] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(value.Length)[0])[0];
            array2[21] = SoftBasic.BuildAsciiBytesFrom(BitConverter.GetBytes(value.Length)[0])[1];
            array2[22] = 48;
            array2[23] = 48;
            array.CopyTo(array2, 24);
            return OperateResult.CreateSuccessResult(array2);
        }

        public static OperateResult CheckResponseLegal(byte[] response)
        {
            if (response.Length < 4)
            {
                return new OperateResult(StringResources.Language.ReceiveDataLengthTooShort);
            }
            if (response[2] == 48 && response[3] == 48)
            {
                return OperateResult.CreateSuccessResult();
            }
            if (response[2] == 53 && response[3] == 66)
            {
                return new OperateResult(Convert.ToInt32(Encoding.ASCII.GetString(response, 4, 2), 16), StringResources.Language.MelsecPleaseReferToManualDocument);
            }
            return new OperateResult(Convert.ToInt32(Encoding.ASCII.GetString(response, 2, 2), 16), StringResources.Language.MelsecPleaseReferToManualDocument);
        }

        public static OperateResult<byte[]> ExtractActualData(byte[] response, bool isBit)
        {
            if (isBit)
            {
                return OperateResult.CreateSuccessResult((from m in response.RemoveBegin(4)
                                                          select (byte)((m != 48) ? 1 : 0)).ToArray());
            }
            return OperateResult.CreateSuccessResult(MelsecHelper.TransAsciiByteArrayToByteArray(response.RemoveBegin(4)));
        }
    }
}
